#include <linux/module.h>

#include <linux/hrtimer.h>
#include <linux/gpio.h>
#include <linux/interrupt.h>

// 全局变量来记录中断发生时间
static ktime_t last_irq_time;
static ktime_t send_irq_time;
static int gpio_num_a = 23;
static int gpio_num_b = 24;
static struct hrtimer irq_test_timer;
#define COUNTS  1000;
 
// 定义一个高精度定时器回调函数
enum hrtimer_restart irq_test_timer_callback(struct hrtimer *timer) {
    // 每1s触发一次GPIO上升沿
    printk("rising gpio 23....\n");
    send_irq_time = ktime_get();
    gpio_set_value(gpio_num_a,1);
    hrtimer_forward(timer, timer->base->get_time(), ns_to_ktime(1000000000));
    return HRTIMER_RESTART;
}
 
// GPIO中断处理函数
irqreturn_t irq_handler(int irq, void *dev_id) {
    // 记录当前时间
    last_irq_time = ktime_get();
    printk("gpio 24 isr....\n");
    gpio_set_value(gpio_num_a,0);
    ktime_t sub_t = ktime_sub(last_irq_time,send_irq_time);
    printk("irq test latency: %lld ns \n", sub_t);
    return IRQ_HANDLED;
}
 
// 初始化GPIO和定时器
static void init_gpio_and_timer(void) {

    //配置GPIO A
    gpio_request(gpio_num_a, "irq_test_a");
    gpio_direction_output(gpio_num_a,0);
    gpio_set_value(gpio_num_a,0);

    ktime_t time1,time2,time;
    time=0;
    int count;
    for(count = 0; count < 1000; count++){
       time1=ktime_get();
       gpio_set_value(gpio_num_a,1);
       time2=ktime_get();
       time += ktime_sub(time2,time1);
       gpio_set_value(gpio_num_a,0);
    }
    time = time/1000;
    printk("irq test latency gpio_set_value: %lld ns \n", time);

    // 配置GPIO B为中断模式
    gpio_request(gpio_num_b, "irq_test_b");
    gpio_direction_input(gpio_num_b);
    request_irq(gpio_to_irq(gpio_num_b), &irq_handler, IRQF_TRIGGER_RISING, "irq_test_b", NULL);

    // 初始化并启动定时器
    hrtimer_init(&irq_test_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
    irq_test_timer.function = &irq_test_timer_callback;
    hrtimer_start(&irq_test_timer, ns_to_ktime(1000000000), HRTIMER_MODE_REL);
}
 
// 在模块初始化函数中调用init_gpio_and_timer
int 
test_irq_latency_init_module(void)
{
   init_gpio_and_timer();

   return 0;
}
void 
test_irq_latency_exit_module(void)
{
   gpio_free(gpio_num_b);
   gpio_free(gpio_num_a);

   printk("test irq latency unloaded IRQ latency test.\n");
}

module_init(test_irq_latency_init_module);
module_exit(test_irq_latency_exit_module);
MODULE_LICENSE("Dual BSD/GPL");
